#include "passwordmanager.h"

// 初始化
PasswordManager PasswordManager::instance;


PasswordManager::PasswordManager()
{
//    OpenSSL_add_all_algorithms();
//    OpenSSL_add_all_ciphers();
//    ERR_load_crypto_strings();
    // 密钥文件存在则不重新创建密钥
//    QString path = QDir::cleanPath(QCoreApplication::applicationDirPath() + QDir::separator() + QString(PUB_KEY_PATH));
//    QString path2 = QDir::cleanPath(QCoreApplication::applicationDirPath() + QDir::separator() + QString(PRI_KEY_PATH));
    QString path = PUB_KEY_PATH;
    QString path2 = PRI_KEY_PATH;
    qDebug() << path <<path2;
    if(Utils::checkFileExists(path) && Utils::checkFileExists(path2)){
        return;
    }
    // 默认用户密码：8888。用户可通过浏览器操作重新生成密钥
    generateRSAKey("8888");
    qDebug() << "密码管理器实例化完成";
}

PasswordManager::~PasswordManager()
{
}

void PasswordManager::generateRSAKey(std::string userKey)
{
    RSA *res = RSA_new();
    BIGNUM *e = BN_new();
    // 设置e的值
    BN_set_word(e, 65537);
    // 生成密钥对
    int ret = RSA_generate_key_ex(res, 1024, e, NULL);
    qDebug() << "ret: " << ret;
    // 提取公钥
    RSA *pub_key = RSAPublicKey_dup(res);
    // 提取私钥
    RSA *pri_key = RSAPrivateKey_dup(res);
    // 将密钥写入磁盘(BIO对象写入)
//    PEM_write_RSAPublicKey()      // 公钥写入磁盘文件
    QString path = PUB_KEY_PATH;
    QString path2 = PRI_KEY_PATH;
//    QString path = QDir::cleanPath(QCoreApplication::applicationDirPath() + QDir::separator() + QString(PUB_KEY_PATH));
    FILE *fp = fopen(path.toStdString().c_str(), "w+");
    PEM_write_RSAPublicKey(fp, pub_key);
    // 私钥写入磁盘文件
//    QString path2 = QDir::cleanPath(QCoreApplication::applicationDirPath() + QDir::separator() + QString(PRI_KEY_PATH));
    FILE *fp2 = fopen(path2.toStdString().c_str(), "w+");
    unsigned char *key = (unsigned char *)userKey.c_str();
    if (!PEM_write_RSAPrivateKey(fp2, pri_key,EVP_aes_128_cbc(),
                              key,userKey.length(), NULL, NULL)) {
        fprintf(stderr, "Write private key failed\n");
    }
//    PEM_write_RSAPrivateKey(fp2, pri_key, NULL, NULL, 0, NULL, NULL);

    // 释放
    fclose(fp);
    fclose(fp2);
    qDebug() << "密钥生成完成";
}

std::string PasswordManager::rsaPriDecrypt(std::string text, RSA * priKey)
{
    if(priKey == nullptr)return "";
//    OpenSSL_add_all_algorithms();
//    OpenSSL_add_all_ciphers();
//    ERR_load_crypto_strings();
    // 先进行解码
//    text = QByteArray::fromBase64(text.c_str()).toStdString();
    QByteArray buf = QByteArray::fromBase64(text.data());
    // 公钥加密
//    text.erase(std::remove(text.begin(), text.end(), '\n'),
//                text.end());
    qDebug() << "待解密的密文：" << QString(buf.toStdString().c_str());
//    unsigned char * from = (unsigned char *)text.c_str();
    unsigned char * from = (unsigned char *)buf.toStdString().c_str();
    char * to = new char[RSA_size(priKey)];
    /**
     * flen: 加解密的数据长度    0 < flen < 加密位数-11, 非对称加密进行的填充
     * from: 明文/密文
     * to: 密文/明文
     * padding: 填充方式，这里使用   RSA_PKCS1_PADDING
     */
    qDebug() << "开始解密" << from;
//    int len = RSA_private_decrypt(text.size(), from, (unsigned char *)to, priKey, RSA_PKCS1_PADDING);
     int len = RSA_private_decrypt(buf.size(), from, (unsigned char *)to, priKey, RSA_PKCS1_PADDING);
    if(len == -1){
        qDebug() << "解密出错";
        return "";
    }
    qDebug() << "解密完成: " << QString(std::string(to, len).c_str());
    return std::string(to, len);
}

std::string PasswordManager::rsaPubEncrypt(std::string text, RSA *pubKey)
{
//    OpenSSL_add_all_algorithms();
//    OpenSSL_add_all_ciphers();
//    ERR_load_crypto_strings();
//    text.erase(std::remove(text.begin(), text.end(), '\n'),
//                text.end());
    if(pubKey == nullptr){
        pubKey = readPublicKey();
    }
    qDebug() << "开始加密: " << QString(text.c_str()) << RSA_size(pubKey);
    char *to = new char[RSA_size(pubKey)];
    int len = RSA_public_encrypt(text.size(), (unsigned char *)text.data(), (unsigned char *)to, pubKey, RSA_PKCS1_PADDING);
    if(len == -1){
        qDebug() << "加密出错";
        return "";
    }
    std::string res = QByteArray(std::string(to, len).c_str()).toBase64().toStdString();
    qDebug() << "加密完成, 密文：" << QString(std::string(to, len).c_str());
    //  返回结果做base64编码存储
    return QByteArray(std::string(to, len).c_str()).toBase64().toStdString();
}

RSA* PasswordManager::readPrivateKey(std::string userKey)
{
    OpenSSL_add_all_algorithms();//密钥有经过口令加密需要这个函数
    qDebug() << "读取私钥...";
//    QString path = QDir::cleanPath(QCoreApplication::applicationDirPath() + QDir::separator() + QString(PRI_KEY_PATH));
    QString path = PRI_KEY_PATH;
    BIO * bio = BIO_new_file(path.toStdString().c_str(), "r");
    RSA *priKey = RSA_new();
    RSA* ret = PEM_read_bio_RSAPrivateKey(bio, &priKey, NULL, (void*)userKey.c_str());
    if(ret == NULL){
        qDebug() << "读取私钥失败";
        return nullptr;
    }
    qDebug() << "读取私钥完成";
    return priKey;
}

RSA *PasswordManager::readPublicKey()
{
    OpenSSL_add_all_algorithms();
    qDebug() << "读取公钥...";
//    QString path = QDir::cleanPath(QCoreApplication::applicationDirPath() + QDir::separator() + QString(PUB_KEY_PATH));
    QString path = PUB_KEY_PATH;
    BIO * bio = BIO_new_file(path.toStdString().c_str(), "r");
    RSA *key = RSA_new();
    RSA *ret = PEM_read_bio_RSAPublicKey(bio, &key, NULL, NULL);
    if(ret == NULL){
        qDebug() << "读取公钥失败";
    }
    qDebug() << "读取公钥完成...";
    return ret;
}
